package com.jiangyg.devtools.execute.code;

import com.intellij.lang.java.JavaLanguage;
import com.intellij.openapi.project.Project;
import com.intellij.ui.EditorTextField;
import com.jiangyg.devtools.DevtoolsException;
import com.jiangyg.devtools.entity.code.BeanDefinition;
import com.jiangyg.devtools.entity.code.TemplateDefinition;
import com.jiangyg.devtools.execute.code.parser.UnitiveBeanDefinitionCreator;
import com.jiangyg.devtools.toolkit.AwtUtils;
import com.jiangyg.devtools.toolkit.CacheUtils;
import com.jiangyg.devtools.toolkit.TemplateUtils;
import com.jiangyg.devtools.ui.AbstractDialogWrapper;
import com.jiangyg.devtools.ui.CodeTextArea;
import com.jiangyg.devtools.ui.EditorTextAreaBuilder;
import com.jiangyg.devtools.ui.MultiTaskPanel;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.*;

/**
 * 类描述：代码生成器弹窗
 *
 * @author jiangyg
 * @date 2023-08-12
 */
public class CodeGeneratorDialogWrapper extends AbstractDialogWrapper {

    private BeanDefinition beanDefinition;

    private final MultiTaskPanel taskPanel = new MultiTaskPanel();

    /**
     * 按钮事件集合
     */
    private final Map<String, Action> actionMap = new LinkedHashMap<>();

    public CodeGeneratorDialogWrapper(@Nullable Project project) {
        super(project);

        init();

        this.setTitle("代码生成器");
        this.setSizeByRatio(0.8, 0.6);

        this.initTaskPanel();
    }

    /**
     * 功能描述：初始化任务面板
     */
    private void initTaskPanel() {
        taskPanel.addTaskComponent("input", new CodeTextArea(true));
        taskPanel.setListener(this::switchTaskEvent);
        taskPanel.showTask("input");
    }

    @Override
    protected @Nullable JComponent createCenterPanel() {
        return taskPanel;
    }

    @Override
    protected Action @NotNull [] createActions() {

        this.setCancelButtonText("关闭");
        this.setOKButtonText("完成并复制");

        // actionMap.put("close", this.getCancelAction());
        actionMap.put("bean", new DirectCreateBeanAction());
        actionMap.put("previous", new PreviousStepAction());
        actionMap.put("property", new CreatePropertyListAction());
        actionMap.put("template", new TemplateSettingAction());
        actionMap.put("code", new CreateCodeAction());
        actionMap.put("complete", this.getOKAction());

        return actionMap.values().toArray(new Action[0]);
    }

    /**
     * 功能描述：切换任务面板回调事件
     *
     * @param step 任务名称
     */
    private void switchTaskEvent(String step) {
        // 输入阶段
        if (StringUtils.equals(step, "input")) {
            showButtonByActionName("bean", "property", "template", "code", "close");
            return;
        }
        // 生成 Bean 代码阶段
        if (StringUtils.equals(step, "bean")) {
            showButtonByActionName("previous", "complete", "close");
            return;
        }
        // 生成 Property 代码阶段
        if (StringUtils.equals(step, "property")) {
            showButtonByActionName("previous", "template", "code", "close");
            return;
        }
        // 生成 Template 代码阶段
        if (StringUtils.equals(step, "template")) {
            showButtonByActionName("previous", "property", "code", "close");
            return;
        }
        // 其他阶段
        showButtonByActionName("previous", "close");
    }

    /**
     * 功能描述：生成代码
     */
    private final class CreateCodeAction extends DialogWrapperAction {

        private CreateCodeAction() {
            super("生成代码");
        }

        @Override
        protected void doAction(ActionEvent e) {
            // 获取模板和Bean属性
            final BeanDefinition definition = getBeanDefinition();
            if (definition == null) {
                AwtUtils.errorTip("没有要生成的代码！");
                return;
            }
            final List<TemplateDefinition> templates = getTemplates();
            // 执行生成逻辑
            new CreateCodeActionImpl(project, definition, templates).exec();
        }

    }

    /**
     * 功能描述：模板设置
     */
    private final class TemplateSettingAction extends DialogWrapperAction {

        private TemplateSettingAction() {
            super("模板设置");
        }

        @Override
        protected void doAction(ActionEvent e) {
            try {
                final String taskName = "template";

                // 获取模板列表
                final List<TemplateDefinition> templates = getTemplates();

                // 如果还未初始化 template 组件，则初始化
                if (!taskPanel.containsTaskComponent(taskName)) {
                    taskPanel.addTaskComponent(taskName, new CodeTemplateTablePanel(project));
                }

                // 获取初始化 template 组件
                final CodeTemplateTablePanel codeTemplateTablePanel = taskPanel.getTaskComponent(taskName);

                // 加载数据
                codeTemplateTablePanel.loadTableData(templates);

                // 显示任务面板
                taskPanel.showTask(taskName);
            } catch (Exception ex) {
                throw new DevtoolsException("设置模板出错", ex);
            }
        }

    }

    /**
     * 功能描述：生成可编辑属性列表
     */
    private final class CreatePropertyListAction extends DialogWrapperAction {

        private CreatePropertyListAction() {
            super("属性列表");
        }

        @Override
        protected void doAction(ActionEvent e) {
            try {
                final String taskName = "property";

                // 获取输入内容并校验
                final BeanDefinition definition = getBeanDefinition();
                if (definition == null) {
                    return;
                }

                // 如果还未初始化 property 组件，则初始化
                if (!taskPanel.containsTaskComponent(taskName)) {
                    taskPanel.addTaskComponent(taskName, new PropertyListTablePanel(project));
                }

                // 获取初始化 property 组件
                final PropertyListTablePanel propertyListTablePanel = taskPanel.getTaskComponent(taskName);

                // 加载数据
                propertyListTablePanel.loadBeanDefinition(definition);

                // 显示任务面板
                taskPanel.showTask(taskName);
            } catch (Exception ex) {
                throw new DevtoolsException("生成属性列表出错", ex);
            }
        }

    }

    /**
     * 类描述：上一步
     */
    private final class PreviousStepAction extends DialogWrapperAction {

        public PreviousStepAction() {
            super("返回");
        }

        @Override
        protected void doAction(ActionEvent e) {
            taskPanel.showPreviousTask();
        }

    }

    /**
     * 类描述：直接生成Bean代码
     */
    private final class DirectCreateBeanAction extends DialogWrapperAction {

        private DirectCreateBeanAction() {
            super("生成Bean代码");
        }

        @Override
        protected void doAction(ActionEvent e) {
            try {
                final String taskName = "bean";

                // 获取输入内容并校验
                final BeanDefinition definition = getBeanDefinition();
                if (definition == null) {
                    return;
                }

                // 如果还未初始化Bean组件，则初始化
                if (!taskPanel.containsTaskComponent(taskName)) {
                    final EditorTextField beanTextArea = EditorTextAreaBuilder.instance()
                            .project(project).defaultFeatures().build(JavaLanguage.INSTANCE);
                    taskPanel.addTaskComponent(taskName, beanTextArea);
                }

                // 获取输入文本域组件和Bean文本域组件
                final EditorTextField beanTextArea = taskPanel.getTaskComponent(taskName);

                // 生成 bean 字符串
                final String resultString = TemplateUtils.template("bean.ftl", definition);
                beanTextArea.setText(resultString);

                // 显示Bean代码
                taskPanel.showTask(taskName);
            } catch (Exception ex) {
                taskPanel.showTask("input");
                throw new DevtoolsException("生成Bean代码出错", ex);
            }
        }

    }

    @Override
    protected void doOKAction() {
        final EditorTextField beanTextArea = taskPanel.getTaskComponent("bean");
        AwtUtils.setClipboardContents(beanTextArea.getText());
        super.doOKAction();
    }

    /**
     * 功能描述：获取代码模板
     *
     * @return 代码模板
     */
    private List<TemplateDefinition> getTemplates() {
        try {
            final List<TemplateDefinition> definitions = CacheUtils.getCodeTemplate();
            if (CollectionUtils.isEmpty(definitions)) {
                return getDefaultTemplates();
            }
            return definitions;
        } catch (Exception ex) {
            throw new DevtoolsException("获取代码模板失败，", ex);
        }
    }

    /**
     * 功能描述：获取默认的模板集合
     *
     * @return 模板集合
     */
    private List<TemplateDefinition> getDefaultTemplates() throws IOException {
        // 定义默认的模板列表
        final List<String> templates = new ArrayList<>();
        templates.add("/ftl/bean.ftl");

        // 生成模板集合
        final List<TemplateDefinition> definitions = new ArrayList<>();
        for (String template : templates) {
            final InputStream stream = this.getClass().getResourceAsStream(template);
            if (stream == null) {
                continue;
            }
            final List<String> lines = IOUtils.readLines(stream, Charset.defaultCharset());

            final TemplateDefinition definition = new TemplateDefinition();
            definition.setUuid(UUID.randomUUID().toString());
            definition.setSelected(true);
            definition.setName(template);
            definition.setContent(StringUtils.join(lines, System.lineSeparator()));
            definition.setPath(StringUtils.EMPTY);

            definitions.add(definition);
        }
        return definitions;
    }

    /**
     * 功能描述：解析 Bean 定义
     *
     * @return Bean定义
     */
    private BeanDefinition getBeanDefinition()  {
        try {
            // 获取输入内容
            final CodeTextArea inputTextArea = taskPanel.getTaskComponent("input");
            final String input = inputTextArea.getText();
            if (!inputTextArea.check()) {
                return null;
            }

            // 根据md5值，判断输入值是否发生变化
            final String md5 = DigestUtils.md5Hex(input);
            if (beanDefinition != null
                    && StringUtils.equals(md5, beanDefinition.getMd5())) {
                // 首先尝试从属性任务面板获取
                final PropertyListTablePanel propertyListTablePanel = taskPanel.getTaskComponent("property");
                if (propertyListTablePanel != null
                        && propertyListTablePanel.getBeanDefinition() != null) {
                    return propertyListTablePanel.getBeanDefinition();
                }
                // 再尝试从缓存取
                return beanDefinition;
            }

            // 解析 bean 定义
            this.beanDefinition = UnitiveBeanDefinitionCreator.build(input).create();
            this.beanDefinition.setMd5(md5);
            return beanDefinition;
        } catch (Exception ex) {
            throw new DevtoolsException("解析Bean属性失败", ex);
        }
    }

    /**
     * 功能描述：显示按钮
     *
     * @param actionNames 按钮名数组
     */
    private void showButtonByActionName(String... actionNames) {
        for (Map.Entry<String, Action> entry : actionMap.entrySet()) {
            final String key = entry.getKey();
            final Action action = entry.getValue();
            if (ArrayUtils.contains(actionNames, key)) {
                switchButtonEnabled(key, true);
                continue;
            }
            switchButtonEnabled(key, false);
        }
    }

    /**
     * 功能描述：切换指定按钮状态
     *
     * @param actionName 事件
     * @param state      状态
     */
    private void switchButtonEnabled(String actionName, boolean state) {
        switchButtonEnabled(actionName, state, state);
    }

    /**
     * 功能描述：切换指定按钮状态
     *
     * @param actionName 事件
     * @param enabled    是否启用
     * @param visible    是否可见
     */
    private void switchButtonEnabled(String actionName, boolean enabled, boolean visible) {
        if (!actionMap.containsKey(actionName)) {
            return;
        }
        final Action action = actionMap.get(actionName);
        final JButton button = getButton(action);
        if (button == null) {
            return;
        }
        button.setVisible(visible);
        button.setEnabled(enabled);
    }

}
